//    Copyright (C) Kherty.  All rights reserved.
using System;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Threading;

namespace OpenLS.UI
{

    public class ApplicationMenu : MenuBase, ICommandSource
    {


        public ICommand Command
        {
            get { return (ICommand)GetValue(CommandProperty); }
            set { SetValue(CommandProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Command.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty CommandProperty =
            DependencyProperty.Register("Command", typeof(ICommand), typeof(ApplicationMenu), new UIPropertyMetadata(null));



        public object CommandParameter
        {
            get { return (object)GetValue(CommandParameterProperty); }
            set { SetValue(CommandParameterProperty, value); }
        }

        // Using a DependencyProperty as the backing store for CommandParameter.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty CommandParameterProperty =
            DependencyProperty.Register("CommandParameter", typeof(object), typeof(ApplicationMenu), new UIPropertyMetadata(null));



        public IInputElement CommandTarget
        {
            get { return (IInputElement)GetValue(CommandTargetProperty); }
            set { SetValue(CommandTargetProperty, value); }
        }

        // Using a DependencyProperty as the backing store for CommandTarget.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty CommandTargetProperty =
            DependencyProperty.Register("CommandTarget", typeof(IInputElement), typeof(ApplicationMenu), new UIPropertyMetadata(null));


        static ApplicationMenu()
        {
            FocusManager.IsFocusScopeProperty.OverrideMetadata(typeof(ApplicationMenu), new FrameworkPropertyMetadata(true));
            DefaultStyleKeyProperty.OverrideMetadata(typeof(ApplicationMenu), new FrameworkPropertyMetadata(typeof(ApplicationMenu)));
            //\\  EventManager.RegisterClassHandler(typeof(ApplicationMenu), Mouse.LostMouseCaptureEvent, new MouseEventHandler(ApplicationMenu.OnLostMouseCapture));
            //EventManager.RegisterClassHandler(typeof(ApplicationMenu), MenuItem.PreviewClickEvent, new RoutedEventHandler(ApplicationMenu.OnMenuItemPreviewClick));
            //EventManager.RegisterClassHandler(typeof(ApplicationMenu), Keyboard.PreviewKeyDownEvent, OnPreviewKeyDown);
            EventManager.RegisterClassHandler(typeof(ApplicationMenu), AccessKeyManager.AccessKeyPressedEvent, new AccessKeyPressedEventHandler(onAccessKey));
            EventManager.RegisterClassHandler(typeof(ApplicationMenu), Selector.SelectionChangedEvent, new SelectionChangedEventHandler(onSelectionChanged));
            EventManager.RegisterClassHandler(typeof(ApplicationMenu), UIElement.MouseLeftButtonDownEvent, new MouseButtonEventHandler((sender, e) =>
                                                                                                                                           {
                                                                                                                                               ApplicationMenu This = (ApplicationMenu)sender;
                                                                                                                                               This.onLeftMouseButtonDown(e);
                                                                                                                                           }), true);

        }

        private  void onLeftMouseButtonDown(MouseButtonEventArgs e )
        {
            if (e.ClickCount == 2)
            {
                var originalSource = e.OriginalSource as Visual;
                // if ((originalSource != null) && (This._mainToggleButton.IsAncestorOf(originalSource) || This._popupToggleButton.IsAncestorOf(originalSource)))
                {
                    if (this.Command != null)
                    {
                        this.Command.Execute(this.CommandParameter);
                    }
                }
            }
        }

        static void onSelectionChanged(object sender, SelectionChangedEventArgs args)
        {
        }
        static void onPreviewMouseUp(object sender, RoutedEventArgs e)
        {
            var This = (ApplicationMenu)sender;
            var originalSource = e.OriginalSource as Button;
            if (originalSource != null)
                This.IsSubmenuOpen = false;
        }



        private static void onMenuItemPreviewClick(object sender, RoutedEventArgs e)
        {
            var This = (ApplicationMenu)sender;
            var originalSource = e.OriginalSource as MenuItem;
            if ((originalSource != null) && !originalSource.StaysOpenOnClick)
            {
                switch (originalSource.Role)
                {
                    case MenuItemRole.TopLevelItem:
                    case MenuItemRole.SubmenuItem:
                        This.IsSubmenuOpen = false;
                       //\\ e.Handled = true;
                        break;
                }
            }
        }
        protected override void OnMouseEnter(MouseEventArgs e)
        {
            base.OnMouseEnter(e);
            IsHighlighted = true;
        }
        protected override void OnMouseLeave(MouseEventArgs e)
        {
            base.OnMouseLeave(e);
            IsHighlighted = false;
        }





        public ApplicationMenu()
        {
            Loaded += onLoaded;
            //\\only once!
            registerPreviewEvent();

        }
        static bool _previewRegistered;
        private static void registerPreviewEvent()
        {
            if (_previewRegistered)
                return;
            _previewRegistered = true;
            EventManager.RegisterClassHandler(typeof (ApplicationMenu), PreviewMouseUpEvent, new RoutedEventHandler(onPreviewMouseUp));
            try
            {
                foreach (RoutedEvent evnt in EventManager.GetRoutedEventsForOwner(typeof(MenuItem)))
                {
                    if (evnt.Name == "PreviewClick")
                    {
                        EventManager.RegisterClassHandler(typeof(ApplicationMenu), evnt, new RoutedEventHandler(onMenuItemPreviewClick));
                        break;
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
        }
        DispatcherTimer _focusTimer;

        void enableFocusTimer()
        {
            if (_focusTimer != null)
                _focusTimer.Stop();
            _focusTimer = new DispatcherTimer {Interval = new TimeSpan(5000)};
            _focusTimer.Tick += delegate
            {
                if (!IsSubmenuOpen)
                    return;
                if (!isDescendant(this, Mouse.Captured as DependencyObject))
                {
                    closeSubmenu();
                }
            };
            _focusTimer.Start();

        }
        void closeSubmenu()
        {
            unHighlight();
            IsSubmenuOpen = false;
            if (_focusTimer != null)
            {
                _focusTimer.Stop();
                _focusTimer = null;
            }
        }

        protected override void OnPreviewKeyDown(KeyEventArgs e)
        {
            base.OnPreviewKeyDown(e);
            Key key = e.Key;
            if (key != Key.Escape && key != Key.System)
            {
                return;
            }
            keyboardLeaveMenuMode();
        }

        private void keyboardLeaveMenuMode()
        {
            unHighlight();
            //\\return;
            closeSubmenu();
        }






        void onLoaded(object sender, RoutedEventArgs e)
        {
            _popup = Template.FindName("SubMenuPopup", this) as Popup;
            _popup.LostFocus += popupLostFocus;
        }

        void popupLostFocus(object sender, RoutedEventArgs e)
        {
            if (isDescendant(this, e.Source as DependencyObject) || isDescendant(_popup, e.Source as DependencyObject))
            {
                Mouse.Capture(_popup, CaptureMode.SubTree);
                return;
            }

             closeSubmenu();
        }
        Popup _popup;

        static bool isDescendant(DependencyObject reference, DependencyObject node)
        {
            var o = node as FrameworkElement;
            while (o != null)
            {
                if (o == reference)
                {
                    return true;
                }
                if (o.Parent != null)
                    o = o.Parent as FrameworkElement;
                else if (o.TemplatedParent != null)
                    o = o.TemplatedParent as FrameworkElement;
                else
                    o = VisualTreeHelper.GetParent(o) as FrameworkElement;
            }
            return false;
        }





        private static void onIsSubmenuOpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var val = (bool)e.NewValue;
            var This = (ApplicationMenu)d;
            if (val)
                This.enableFocusTimer();
            else
            {
                This.unHighlight();
                This.disableFocusTimer();
            }
        }

        private void unHighlight()
        {
           //\\ return;
            foreach (Control control in Items)
            {
                if (control is MenuItem)
                {
                    var item = (MenuItem)control;
                   /* MouseEventArgs args = new MouseEventArgs(InputManager.Current.PrimaryMouseDevice, 0);
                    args.RoutedEvent = MenuItem.MouseLeaveEvent;
                    control.RaiseEvent(args);
                   */
                    //object o = typeof(MenuItem).GetField("IsHighlightedPropertyKey", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic).GetValue(null);
                   //\\ item.SetValue((DependencyPropertyKey)o, false);
                    item.SetValue(Selector.IsSelectedProperty, false);
                    SetValue(Selector.SelectedIndexProperty, -1);
                    Contract.Assert(!item.IsHighlighted);
                }
            }
        }

        private void disableFocusTimer()
        {
            if (_focusTimer != null)
            {
                _focusTimer.Stop();
                _focusTimer = null;
            }
        }
        private static object coerceIsSubmenuOpen(DependencyObject d, object value)
        {
            if ((bool)value)
            {
                var item = (ApplicationMenu)d;
                if (!item.IsLoaded)
                {
                    //\\ item.RegisterToOpenOnLoad();
                    //\\ return BooleanBoxes.FalseBox;
                }
            }
            return value;
        }


        public object Header
        {
            get { return GetValue(HeaderProperty); }
            set { SetValue(HeaderProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Header.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty HeaderProperty =
            DependencyProperty.Register("Header", typeof(object), typeof(ApplicationMenu), new UIPropertyMetadata(null));


        protected override void HandleMouseButton(MouseButtonEventArgs e)
        {
            base.HandleMouseButton(e);
            if (e.ButtonState == MouseButtonState.Pressed && e.ChangedButton == MouseButton.Left)
            {
                //\\ e.Handled = true;
                if (IsSubmenuOpen)
                {

                    closeSubmenu();
                    return;
                }
                else
                {
                    openSubMenu();
                }
            }
        }









        public bool IsSubmenuOpen
        {
            get { return (bool)GetValue(IsSubmenuOpenProperty); }
            set { SetValue(IsSubmenuOpenProperty, value);
        }
        }

        // Using a DependencyProperty as the backing store for IsSubmenuOpen.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsSubmenuOpenProperty =
            DependencyProperty.Register("IsSubmenuOpen", typeof(bool), typeof(ApplicationMenu), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, onIsSubmenuOpenChanged, coerceIsSubmenuOpen));

        public bool IsHighlighted
        {
            get { return (bool)GetValue(IsHighlightedProperty); }
            set { SetValue(IsHighlightedProperty, value); }
        }

        // Using a DependencyProperty as the backing store for IsHighlighted.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsHighlightedProperty =
            DependencyProperty.Register("IsHighlighted", typeof(bool), typeof(ApplicationMenu), new FrameworkPropertyMetadata(false));

        public object RightContent
        {
            get { return GetValue(RightContentProperty); }
            set { SetValue(RightContentProperty, value); }
        }

        // Using a DependencyProperty as the backing store for RightContent.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty RightContentProperty =
            DependencyProperty.Register("RightContent", typeof(object), typeof(ApplicationMenu), new UIPropertyMetadata(null));




        public object Footer
        {
            get { return GetValue(FooterProperty); }
            set { SetValue(FooterProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Footer.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty FooterProperty =
            DependencyProperty.Register("Footer", typeof(object), typeof(ApplicationMenu), new UIPropertyMetadata(null));



        public string AccessKey
        {
            get { return (string)GetValue(AccessKeyProperty); }
            set { SetValue(AccessKeyProperty, value); }
        }

        // Using a DependencyProperty as the backing store for AccessKey.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty AccessKeyProperty =
            DependencyProperty.Register("AccessKey", typeof(string), typeof(ApplicationMenu), new UIPropertyMetadata(null, onAccessKeyChanged));
        static void onAccessKeyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var This = (ApplicationMenu)d;
            var oldValue = e.OldValue as string;
            var newValue = e.NewValue as string;
            if (oldValue != null)
                AccessKeyManager.Unregister(oldValue, This);
            if (newValue != null)
                AccessKeyManager.Register(newValue, This);
        }
        static void onAccessKey(object sender, AccessKeyPressedEventArgs args)
        {
            var This = (ApplicationMenu)(sender);
            if (args.Key == This.AccessKey &&( Keyboard.Modifiers & ModifierKeys.Alt) == ModifierKeys.Alt)
                This.openSubMenu();

        }

        private void openSubMenu()
        {
            IsSubmenuOpen = true;
            Mouse.Capture(_popup);
            Keyboard.Focus(this);
            unHighlight();

        }


    }
}
